package net;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HttpConnection;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.provider.SyncStateContract.Constants;
import android.util.Log;

import com.vms.data.CheckerLocation;
import com.vms.data.GSMNetworkInfo;

public class Downloader {
	private byte[] data;
	public static int TIME_OUT = 5000;
	private static Hashtable<Long, Thread> sessions = new Hashtable<Long, Thread>();
	
	private static Downloader instance;
	private DefaultHttpClient client;
	public void getDataUsingHttp(String session, String url, String method, Hashtable params, IDownloader listener, int downloadsize) {
		if (!params.contains("user_id"))
			params.put("user_id", "" + GSMNetworkInfo.getInstance(null).getIMEI());
		if (!params.contains("lac"))
			params.put("lac", "" + GSMNetworkInfo.getInstance(null).getLAC());
		if (!params.contains("cellid"))
			params.put("cellid", "" + GSMNetworkInfo.getInstance(null).getCellID());
		if (!params.contains("lat"))
			params.put("lat", "" + CheckerLocation.getInstance(null).getLatitude());
		if (!params.contains("long"))
			params.put("long", "" + CheckerLocation.getInstance(null).getLongitude());
		if (!params.contains("rxl"))
			params.put("rxl", "" + GSMNetworkInfo.getInstance(null).getSignalStreght());
		
		if (!params.contains("evdo"))
			params.put("evdo", "" + GSMNetworkInfo.getInstance(null).getEVDO());
		if (!params.contains("ecio"))
			params.put("ecio", "" + GSMNetworkInfo.getInstance(null).getECIO());
		if (!params.contains("snr"))
			params.put("snr", "" + GSMNetworkInfo.getInstance(null).getSNR());
		if (!params.contains("neighbour"))
			params.put("neighbour", "" + GSMNetworkInfo.getInstance(null).getNeighbourCells());
		if (!params.contains("biterrorrate"))
			params.put("biterrorrate", "" + GSMNetworkInfo.getInstance(null).getBitErrorRate());

		post(session, url, params, listener, downloadsize);
	}

	public void getDataUsingHttp(String session, String url, String method, Hashtable params, IDownloader listener) {
		stopall();
		getDataUsingHttp(session, url, method, params, listener, -1);
	}

	private Downloader() {
		HttpParams defaulParams = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(defaulParams, TIME_OUT);		
		client = new DefaultHttpClient(defaulParams);
	}
	
	public static Downloader getInstance() {
		if (instance == null)
			instance = new Downloader();
		return instance;
	}
	public static void delete()
	{
		instance = null;
	}
	public static void stop(long sessionId) {
		Thread thread = sessions.get(sessionId);
		if (thread != null)	thread.interrupt();
	}
	
	public static void stopall()
	{
		for(int sessionId = 0; sessionId < sessions.size(); sessionId ++)
		{
			Thread thread = sessions.get(sessionId);
			if (thread != null)	thread.interrupt();
		}
	}
	static void throwError() throws IOException {
		throw new IOException();
	}
	
	public DownloadResult get(String url, Hashtable<String, Object> params,int downloadsize) throws InterruptedException {
		HttpPost request = new HttpPost(url);
		request.setHeader("Content-Type", "application/x-www-form-urlencoded"); 		
		List<NameValuePair> httpParams = new ArrayList<NameValuePair>();
		if (params != null) {
			for(Enumeration<String> keys = params.keys(); keys.hasMoreElements();) {
				String key = keys.nextElement();
				httpParams.add(new BasicNameValuePair(key, params.get(key).toString()));
			}	
		}
		Log.i("NET",url + "\t" + httpParams.toString());
		try {
			request.setEntity(new UrlEncodedFormEntity(httpParams));
			final HttpResponse response;
			ByteArrayOutputStream bos;
			
			
			synchronized (client) {
				response = client.execute(request);
				InputStream instream = response.getEntity().getContent();
				
				int status = response.getStatusLine().getStatusCode();
				if (status != 200) throwError();

				bos = new ByteArrayOutputStream();
				final byte[] buf = new byte[512]; 
				int len = 0;
				while ((len = instream.read(buf, 0, buf.length)) != -1) {
					Thread.sleep(0);
					bos.write(buf, 0, len);
				}
				bos.close();
			}
						
			return new DownloadResult(IDownloader.DOWNLOADED, bos.toByteArray());
		} catch (IOException e) {
			e.printStackTrace();
			return new DownloadResult(IDownloader.ERROR);
		}
	}
	
	public void post(String session, String url, Hashtable<String, Object> params, IDownloader listener,int downloadsize) {
		Thread thread = new Thread(new AsyncSender(session, client, listener, url, params, downloadsize));
		thread.start();
		sessions.put(thread.getId(), thread);
	}
	
	class AsyncSender extends Thread {
		private HttpClient client;
		private String url;
		private IDownloader listener;
		private List<NameValuePair> httpParams;
		private String session;
		int downloadsize;
		protected AsyncSender(String session, HttpClient client, IDownloader listener, String url, Hashtable<String, Object> params,int downloadsize)
		{
			this.client = client;
			this.listener = listener;
			this.url = url;
			this.httpParams = new ArrayList<NameValuePair>();
			this.session = session;
			this.downloadsize = downloadsize;
			
			if (params != null) {
				for(Enumeration<String> keys = params.keys(); keys.hasMoreElements();) {
					String key = keys.nextElement();
					this.httpParams.add(new BasicNameValuePair(key, params.get(key).toString()));
				}					
			}
		}

		public void run() {
			long sessionId = Thread.currentThread().getId();
			listener.DownloadChanged(session, IDownloader.CONNECTING, url, -1, -1);
			
			HttpPost request = new HttpPost(url);
			request.setHeader("Accept-Encoding", "gzip");
			request.setHeader("Content-Type", "application/x-www-form-urlencoded");
			try {
				request.setEntity(new UrlEncodedFormEntity(httpParams)); 				
				final HttpResponse response;
				ByteArrayOutputStream bos;
				Log.i("NET",url + "\t" + httpParams.toString());
				synchronized (client) {			
					response = client.execute(request);
					InputStream instream = response.getEntity().getContent();
					
					listener.DownloadChanged(session, IDownloader.CONNECTED, url, -1, -1);
					
					Header contentEncoding = response.getFirstHeader("Content-Encoding");
					if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip"))
					    instream = new GZIPInputStream(instream);
					
					int status = response.getStatusLine().getStatusCode();
					
//					if (status != 200) throwError();
					
					
					
					int length = -1;
					Header contentLength = response.getFirstHeader("Content-Length");
					if (contentLength != null)
						length = Integer.parseInt(contentLength.getValue());
					
					bos = new ByteArrayOutputStream();
					final byte[] buf = new byte[512]; 
					int len = 0;
					int count = 0;
					while ((len = instream.read(buf, 0, buf.length)) != -1 && (downloadsize == -1 || ((downloadsize != -1) && (count > downloadsize)))) {
//						Thread.sleep(0);
						bos.write(buf, 0, len);
						count +=len;
						listener.DownloadChanged(session, IDownloader.DOWNLOADING, url, bos.size(), length);
					}
					try {
						instream.close();
						response.getEntity().consumeContent();
					} catch (Exception e) {
					}
				}
				Downloader.this.data = bos.toByteArray();
				listener.DownloadChanged(session, IDownloader.DOWNLOADED, url, bos.size(), bos.size());
				
			} catch (IOException e) {
				e.printStackTrace();
				listener.DownloadChanged(session, IDownloader.ERROR, url, -1,-1);
			}
		}
	}

	public byte[] getData() {
		return data;
	}
}
